/* This program allows a user to build a generalised delta rule net */
/* for supervised learning. User can specify number of input and    */
/* output units, number of hidden layers and number of units in     */
/* each hidden layer. 						    */
/*								    */
/* After the net is built, learning takes place in the net with a   */
/* given set of training samples.  User specifies values of the     */
/* learning rate eta, the momentum rate alpha, maximum tolerance    */
/* errors and maximum number of iterations. 			    */
/* 								    */
/* After learning, all the information relevent to the structure of */
/* the net, including weights and thresholds are stored in files    */
/* 								    */
/* Outputs can be generated for new patterns by reading from files  */
/* and by reconstructing the net.			  	    */



/* All include header files needed in the program are included here */

#include <stdio.h>
#include <math.h>
#include <ctype.h>


/* ----------- All define constants used in the program ----------- */

#define		SEXIT		3    /* Exit successfully 	    */
#define		RESTRT		2    /* Restart			    */
#define 	FEXIT	 	1    /* Exit in failure 	    */
#define 	CONTINUE 	0    /* Continue Calculation	    */


/* ------------ All the variables used in the program ------------- */

float eta;			/* Learning rate 		    */
float alpha;			/* Momentum rate		    */
float err_curr;			/* Normalised system error	    */
float maxe; 			/* Maximum allowed system error     */
float maxep;			/* Maximum allowed pattern error    */
float **wtptr;			/* Weights in the net		    */
float **outptr;			/* Outputs of all the nodes 	    */
float **errptr;			/* Errors are held in this	    */
float **delw;			/* Change in weights 		    */
float **target;			/* Required outputs 		    */
float **wtarget;                /* scaling factor 		    */
float **winput;                 /* scaling factor for               */
float **input, *ep;		/* Inputs to net & pattern errors   */
float **outpt;			/* Outputs obtained by the net      */
int   *nunit;			/* Number of units in each layer    */
int   nhlayer, ninput;		/* Number of hidden layers, inputs  */
int   ninattr, noutattr; 	/* No of input & output attributes  */
int   store_after;		/* When to store weights to restart */
int   result, cnt, cnt_num;
int   nsnew, nsold;
char  task_name[40];		/* Current working taskname	    */
FILE  *fp1, *fp2;
FILE  *fp3, *fp4, *fscale;
FILE  *fopen();
int   fplot10;
long  randseed;


/* ----------- This function generates a random number ------------ */


int random()
{
	randseed = 15625L * randseed + 22221L;
	return((randseed >> 16) & 0x7fff);
}


/*------- This function allocates dynamic memory for the net ----- */

void init()
{
    int len1, len2, i, k;
    float *p1, *p2, *p3, *p4;

    len1 = len2 = 0;
    nunit[nhlayer+2] = 0;

    for(i = 0; i < (nhlayer +2); i++)
    {
	len1 += (nunit[i] + 1) * nunit[i+1];
     	len2 += nunit[i] + 1;
    }

    /* Here allocation is done for weights, outputs, errors and     */
    /* change in weights.					    */

    wtptr = (float **) calloc(nhlayer+1, sizeof(float *));
    outptr = (float **) calloc(nhlayer+2, sizeof(float *));
    errptr = (float **) calloc(nhlayer+2, sizeof(float *));
    delw = (float **) calloc(nhlayer+1, sizeof(float *));

    p1 = (float *) calloc(len1+1, sizeof(float));
    p2 = (float *) calloc(len2+1, sizeof(float));
    p3 = (float *) calloc(len2+1, sizeof(float));
    p4 = (float *) calloc(len1+1, sizeof(float));

    if((wtptr==NULL)||(outptr==NULL)||(errptr==NULL)||(delw==NULL)||(p1==NULL)||(p2==NULL)||(p3==NULL)||(p4==NULL))
    {
       printf("Could not allocate memory\n");
       exit(1);
    }
    /* Set up the initial pointers to the above allocated 2D arrays */

    wtptr[0] = p1;
    outptr[0] = p2;
    errptr[0] = p3;
    delw[0] = p4;

    /* Set up all the other pointers appropriately		    */

    for(i = 1; i < (nhlayer + 1); i++)
    {
	wtptr[i] = wtptr[i-1] + nunit[i] * (nunit[i-1] + 1);
	delw[i] = delw[i-1] + nunit[i] * (nunit[i-1] + 1);
    }

    for(i = 1; i < (nhlayer + 2); i++)
    {
	outptr[i] = outptr[i-1] + nunit[i-1] + 1;
   	errptr[i] = errptr[i-1] + nunit[i-1] + 1;
    }

    /* Initialize thresholds in the net				    */

    for(i = 0; i < (nhlayer +1); i++)
    {
	*(outptr[i] + nunit[i]) = 1.0;
    }
}



/* - Initialize weights with random numbers between -0.5 and +0.5 - */

void initwt()
{
    int i, j;

    for(j = 0; j < (nhlayer + 1); j++)
    {
	for(i = 0; i < (nunit[j] +1) * nunit[j+1]; i++)
	{
	    *(wtptr[j] + i) = random()/pow(2.0, 15.0) -0.5;
	    *(delw[j] + i) = 0.0;
	}
    }
    cnt = 0;
}



/* - Restore weights with the values stored in file Suffix_store -  */

void restorewt()
{
    int i, j;
    char var_file_name[40];
    FILE *fp5;

    strcpy(var_file_name, task_name);
  strcat(var_file_name, "_store.dat");
    if((fp5 = fopen(var_file_name, "r")) == NULL)
    {
	perror("\nCannot open store file ");
	exit(0);
    }

    for(j = 0; j < (nhlayer + 1); j++)
    {
	for(i = 0; i < (nunit[j] +1) * nunit[j+1]; i++)
	{
	    fscanf(fp5, "%f", (wtptr[j] + i));
	    fscanf(fp5, "%f", (delw[j] + i));
	}
    }
    fscanf(fp5, "%d", &cnt);
    fclose(fp5);
}



/* - Store weights with the current values in file Suffix_store -   */

void storewt()
{
    int i, j;
    char var_file_name[40];
    FILE *fp5;

    strcpy(var_file_name, task_name);
    strcat(var_file_name, "_store.dat");
    if((fp5 = fopen(var_file_name, "w")) == NULL)
    {
	perror("\nCannot open store file ");
	exit(0);
    }

    for(j = 0; j < (nhlayer + 1); j++)
    {
	for(i = 0; i < (nunit[j] +1) * nunit[j+1]; i++)
	{
	    fprintf(fp5, "%35.33f  ", *(wtptr[j] + i));
	    fprintf(fp5, "%35.33f\n", *(delw[j] + i));
	}
    }
    fprintf(fp5, "\n%d", cnt);
    fclose(fp5);
}



/* In this function, we specify architecture of the net & values of */
/* learning parameters						    */

void set_up()
{
    int i;

    printf("When you dont have any specific value \n");
    printf("Enter the value given by default\n\n");

    printf("\nLearning rate eta (default = 0.9) ? : ");
    scanf("%f", &eta);
    printf("\neta %f\n", eta);

    printf("\nMomentum rate alpha (default = 0.7) ? : ");
    scanf("%f", &alpha);
    printf("\nalpha %f\n", alpha);

    printf("\nMax total error (default = 0.01) ? : ");
    scanf("%f", &maxe);
    printf("\nTotal error %12.11f\n", maxe);
    printf("\nMax individual error (default = 0.001) ? : ");
    scanf("%f", &maxep);
    printf("\nIndividual error%12.11f\n", maxep);

    printf("\nMax number of iterations (default = 1000) ? : ");
    scanf("%d", &cnt_num);
    printf("\nNumber of iterations%d\n", cnt_num);

    printf("\nNumber of hidden layers ? : ");
    scanf("%d", &nhlayer);

    /* Allocate memory for holding number of units in each layer    */
    /* and initializing it by the values specified by the user	    */

    nunit = (int *) calloc(nhlayer+3, sizeof(int));
    if(nunit==NULL)
    {
       printf("memory allocation problem at nunit\n");
       exit(1);
    }

    for(i = 0 ; i < nhlayer; i++)
    {
	printf("\n\tNumber of units for hidden layer %d ? : ", i+1);
	scanf("%d", &nunit[i+1]);
    }

    printf("\nCreate error file ? If so type 1, or type 0 : ");
    scanf("%d", &fplot10);

    printf("\nEnter the seed for random() number generator? : ");
    scanf("%d", &randseed);

    printf("\nEnter the number of iterations after which \n");
    printf("            weights should be stored? : ");
    scanf("%d", &store_after);

    printf("Execution starts\n");

    nunit[nhlayer+1] = noutattr;
    nunit[0] = ninattr;
}


/* This function reads file for net architecture and learning 	    */
/* parameters.  File name is suffix_v.dat			    */

void dread(taskname)
char *taskname;
{
    int i, j, c;
    char var_file_name[40];

    strcpy(var_file_name, taskname);
    strcat(var_file_name, "_v.dat");
    if((fp1 = fopen(var_file_name, "r")) == NULL)
    {
	perror("\nCannot open data file ");
	exit(0);
    }

    fscanf(fp1, "%d%d%d%f%f%d%d", &ninput, &noutattr, &ninattr, &eta,
		&alpha, &nhlayer, &cnt_num);

    nunit = (int *) calloc(nhlayer+3, sizeof(int));
    if(nunit==NULL)
    {
       printf("Memory problem in nunit\n");
       exit(1);
    }

    for(i = 0 ; i < nhlayer + 2; i++)
	fscanf(fp1, "%d", &nunit[i]);

    if((c = fclose(fp1)) != 0)
   	printf("\nFile cannot be closed %d ", c);
}



/* This function reads file containing weights and thresholds, File */
/* name has suffix_w.dat.					    */

void wtread(taskname)
char *taskname;
{
    int i, j, c;
    char wt_file_name[40];

    strcpy(wt_file_name, taskname);
    strcat(wt_file_name, "_w.dat");
    if((fp2 = fopen(wt_file_name, "r")) == NULL)
    {
	perror("Cannot open data file ");
	exit(0);
    }

    for(i = 0; i < nhlayer + 1; i++)
    {
	for(j = 0; j < (nunit[i] + 1) * nunit[i+1]; j++)
	{
	    fscanf(fp2, "%f", (wtptr[i] + j));
	}
    }
    if((c = fclose(fp2)) != 0)
	printf("\nFile cannot be closed %d ", c);
}



/* Create file for net architecture and learning parameters, file   */
/* name has suffix_v.dat.					    */

void dwrite(taskname)
char *taskname;
{
    int i, j, c;
    char var_file_name[40];

    strcpy(var_file_name, taskname);
    strcat(var_file_name, "_v.dat");
    if((fp1 = fopen(var_file_name, "w+")) == NULL)
    {
	perror("\nCannot open data file ");
	exit(0);
    }

    fprintf(fp1, "%u %u %u %f %f %u %u\n", ninput, noutattr, ninattr, eta,
		 alpha, nhlayer, cnt_num);

    for(i = 0 ; i < nhlayer + 2; i++)
    {
	fprintf(fp1, "%d ", nunit[i]);
    }
    fprintf(fp1, "\n%d %f", cnt, err_curr);
    fprintf(fp1, "\n");

    for(i = 0; i < ninput; i++)
    {
	for(j = 0; j < noutattr; j++)
	{
	    fprintf(fp1, "%f    ", outpt[i][j]);
	}
	fprintf(fp1, "\n");
    }

    if((c = fclose(fp1)) != 0)
   	printf("\nFile cannot be closed %d ", c);
}



/* Create file for saving weights and thresholds learned from 	    */
/* training.  File name has suffix_w.dat.			    */

void wtwrite(taskname)
char *taskname;
{
    int i, j, c, k;
    char wt_file_name[40];

    strcpy(wt_file_name, taskname);
    strcat(wt_file_name, "_w.dat");
    if((fp2 = fopen(wt_file_name, "w+")) == NULL)
    {
	perror("Cannot open data file ");
	exit(0);
    }

    k = 0;
    for(i = 0; i < nhlayer + 1; i++)
    {
	for(j = 0; j < (nunit[i] + 1) * nunit[i+1]; j++)
	{
	    if(k == 8)
	    {
		k = 0;
		fprintf(fp2, "\n");
	    }
	    fprintf(fp2, "%f ", *(wtptr[i] + j));
      	    k++;
	}
    }
    if((c = fclose(fp2)) != 0)
	printf("\nFile cannot be closed %d ", c);
}



/* ------ Bottom_up calculation of net for input pattern --------   */

void forward(i)
int i;
{
    int m, n, p, offset;
    float net;

    /* Input level output calculation				    */

    for(m = 0; m < ninattr; m++)
	*(outptr[0] + m) = input[i][m];

    /* Hidden and output layer output calculations		    */

    for(m = 1; m < nhlayer + 2; m++)
    {
	for(n = 0; n < nunit[m]; n++)
	{
	    net = 0.0;
	    for(p = 0; p < nunit[m-1] + 1; p++)
	    {
		offset = (nunit[m-1] + 1) * n + p;
		net += *(wtptr[m-1] + offset) * ( *(outptr[m-1] + p));
	    }
	    *(outptr[m] + n) = 1/(1 + exp(-net));
	}
    }
    for(n = 0; n < nunit[nhlayer+1]; n++)
	outpt[i][n] = *(outptr[nhlayer+1] + n);
}



/* In this function several conditions are checked to see whether   */
/* learning should be terminated or not 			    */

int introspective(nfrom, nto)
int nfrom, nto;
{
    int i, flag;

    /* Reached maximum number of iterations			    */

    if(cnt >= cnt_num)
	return(FEXIT);

    /* Check if error for each pattern is small enough		    */

    nsnew = 0;
    flag = 1;
    for(i = nfrom; (i < nto) && (flag == 1); i++)
    {
	if(ep[i] <= maxep)
	    nsnew++;
	else
	    flag = 0;
    }
    if(flag == 1) return(SEXIT);

    /* Check if system total error is small enough		    */

    if(err_curr <= maxe)
	return(SEXIT);

    /* Storing the weights one's in 10 iterations 		    */

    if((cnt % store_after) == 0)
    {
	storewt();
    }

    return(CONTINUE);
}



/* In this function forward pass is applied and error is propogated */
/* back by GDR							    */

int rumelhart(from_snum, to_snum)
int from_snum;
int to_snum;
{
    int i, j, k, m, n, p, offset, index;
    float out;
    char err_file[40];

    nsold = 0;
    result = CONTINUE;

    strcpy(err_file, task_name);
    strcat(err_file, "_err.fun");

    do
    {
	err_curr = 0.0;

	for(i = from_snum; i < to_snum; i++)
  	{
	    /* Bottom_up calculation				    */

	    forward(i);

	    /* Top_down error propogation			    */

 	    /* Output level error				    */

 	    for(m = 0; m < nunit[nhlayer+1]; m++)
	    {
		out = *(outptr[nhlayer+1] + m);
		*(errptr[nhlayer+1]+m) = (target[i][m]-out)*(1-out)*out;
	    }

	    /* Hidden and input layer errors			    */

	    for(m = nhlayer+1; m >= 1; m--)
	    {
		for(n = 0; n < nunit[m-1]+1; n++)
		{
		    *(errptr[m-1]+n) = 0.0;
		    for(p = 0; p < nunit[m]; p++)
		    {
			offset = (nunit[m-1]+1) * p + n;
			*(delw[m-1]+offset) = eta * (*(errptr[m]+p)) *
			  (*(outptr[m-1]+n)) + alpha *
			   (*(delw[m-1]+offset));

			*(errptr[m-1]+n) += *(errptr[m]+p) *
			  (*(wtptr[m-1]+offset));

		    }
		    *(errptr[m-1]+n) = *(errptr[m-1]+n) *
		      (1 - *(outptr[m-1]+n)) * (*(outptr[m-1]+n));
		}
	    }

	    /* Weight changes are done here			    */

 	    for(m = 1; m < nhlayer + 2; m++)
	    {
		for( n = 0; n < nunit[m]; n++)
		{
		    for(p = 0; p < nunit[m-1] + 1; p++)
		    {
			offset = (nunit[m-1] + 1) * n + p;
			*(wtptr[m-1] + offset) += *(delw[m-1] + offset);
		    }
		}
	    }

 	    ep[i] = 0.0;
	    for(m = 0; m < nunit[nhlayer+1]; m++)
	    {
		ep[i] += fabs((target[i][m] - *(outptr[nhlayer+1] + m)));
	    }

	    /* Normalized system error				    */

	    err_curr += ep[i] * ep[i];
	}
	err_curr = 0.5 * err_curr / ninput;

    	if(fplot10 == 1)
	{
	    if((fp3 = fopen(err_file, "a")) == NULL)
	    {
		perror("Cannot open error file\n");
		exit(0);
	    }
	    fprintf(fp3, "%d, %2.9f\n", cnt, err_curr);
	    fclose(fp3);
	}
	cnt++;

	/* Check for terminating learning			    */

    	result = introspective(from_snum, to_snum);
    } while(result == CONTINUE);

    /* Update outputs with changed weights			    */

    for(i = from_snum; i < to_snum; i++) forward(i);

    for(i = 0; i < nhlayer+1; i++)
    {
	index = 0;
	for(j = 0; j < nunit[i+1]; j++)
	{
	    printf("\n\nWeights between unit %d of layer %d ",
		    j, i+1);
	    printf(" and units of layer %d\n", i);
	    for(k = 0; k < nunit[i]; k++)
	    {
		printf("  %f", *(wtptr[i] + index++));
	    }
	    printf("\n Threshold of unit %d of layer %d is %f ",
		    j, i+1, *(wtptr[i] + index++));
	}
    }

    for(i = 0; i < ninput; i++)
    {
	for(j = 0; j < noutattr; j++)
	{
	    outpt[i][j]=outpt[i][j]*(wtarget[j][0] - wtarget[j][1])+wtarget[j][1];
	    target[i][j]=target[i][j]*(wtarget[j][0] - wtarget[j][1])+wtarget[j][1];

	    printf("\n\n Sample %d output %d = %f target %d = %f",
		    i, j, outpt[i][j], j, target[i][j]);
	}
    }



    printf("\n\nTotal number of iterations is %d", cnt);
    printf("\nNormalized system error is %f\n\n\n", err_curr);
    return(result);
}



/* Read in the input data file specified by user		    */

void user_session()
{
    int i, j, showdata;
    char fnam[40], dtype[40];
    FILE *fpin, *fpout;

    printf("\n Start of learning session");

    printf("\n\t Enter the task name : ");
    scanf("%s", task_name);

    printf("\nHow many features in input pattern ? : ");
    scanf("%d", &ninattr);

    printf("\nHow many output units ? : ");
    scanf("%d", &noutattr);

    printf("\nTotal number of input samples ? : ");
    scanf("%d", &ninput);

    input = (float **) calloc(ninput, sizeof(float *));
    target = (float **) calloc(ninput, sizeof(float *));
    wtarget = (float **) calloc(noutattr, sizeof(float *));
    winput  = (float **) calloc(ninattr,sizeof(float *));

    if((input==NULL)||(target==NULL)||(wtarget==NULL)||(winput==NULL))
    {
       printf("Memory problem in input .. etc\n");
       exit(1);
    }

    for(i = 0; i < ninput; i++)
    {
	input[i] = (float *) calloc(ninattr, sizeof(float));
 	target[i] = (float *) calloc(noutattr, sizeof(float));
        if((input[i]==NULL)||(target[i]==NULL))
        {
           printf("Memory problem in input/target at %d\n",i);
           exit(1);
        } 
    }

    for(i = 0; i < noutattr; i++)
    {
	wtarget[i] = (float *) calloc(2, sizeof(float));
        if(wtarget[i]==NULL)
        {
           printf("Memory problem in wtarget at %d\n",i);
           exit(1);
        } 
    }

    for (i=0; i < ninattr; i++)
    {
       winput[i] = (float *) calloc (2,sizeof(float));
       if(winput[i]==NULL)
       {
           printf("Memory problem in winput at %d\n",i);
           exit(1);
       } 
    }
    strcpy(fnam, task_name);
    strcat(fnam, ".dat");
    printf("\nInput file name is %s ", fnam);
    if((fpin = fopen(fnam, "r")) == NULL)
    {
	printf("\nFile %s does not exist", fnam);
	exit(0);
    }
    strcpy(fnam, task_name);
    strcat(fnam, ".out");
    printf("\nOutput file name is %s ", fnam);
    if((fpout = fopen(fnam, "r")) == NULL)
    {
	printf("\nFile %s does not exist", fnam);
	exit(0);
    }

    printf("\n Do you want to look at data just read ? ");
    printf("\n Answer yes or no \n");
    scanf("%s", dtype);
    showdata = ((dtype[0] == 'y') || (dtype[0] == 'Y'));
    if(showdata)
    {
    	for(i = 0; i < ninput; i++)
    	{
	    for(j = 0; j < ninattr; j++)
	    {
	        fscanf(fpin, "%f", &input[i][j]);
		printf("%f ", input[i][j]);
	    }

	    for(j = 0; j < noutattr; j++)
	    {
	        fscanf(fpout, "%f", &target[i][j]);
		printf("%f ", target[i][j]);
 	    }
	    printf("\n");

        }
    }
    else
    {
    	for(i = 0; i < ninput; i++)
    	{
	    for(j = 0; j < ninattr; j++)
	    {
	        fscanf(fpin, "%f", &input[i][j]);
 	    }
	    for(j = 0; j < noutattr; j++)
	    {
	        fscanf(fpout, "%f", &target[i][j]);
 	    }
        }
    }


    for(i = 0; i < noutattr; i++)
	{
	 wtarget[i][0]=-99999.0;
	 wtarget[i][1]=99999.0;
	}

    for (i=0; i< ninattr; i++)
    {
    winput[i][0] = -99999.0;
    winput[i][1] = 99999.0;
    }

    for(i = 0; i < ninput; i++)
	{
	    for(j = 0; j < noutattr; j++)
	    {
	      if(wtarget[j][0]<target[i][j]) wtarget[j][0]=target[i][j];
	      if(wtarget[j][1]>target[i][j]) wtarget[j][1]=target[i][j];
 	    }
	}


         for(i = 0; i < ninput; i++)
	{
	    for(j = 0; j < noutattr; j++)
	    {
              if((wtarget[j][0]-wtarget[j][1])==0)
	      {
		printf("division by zero. line no 797.\n");
		exit(1);
	      }
	      else	
	       target[i][j] = (target[i][j] - wtarget[j][1])/(wtarget[j][0]-wtarget[j][1]);
 	    }
	}


        for(i = 0; i < ninput; i++)
	{
	    for(j = 0; j < ninattr; j++)
	    {
	      if(winput[j][0]<input[i][j]) winput[j][0]=input[i][j];
	      if(winput[j][1]>input[i][j]) winput[j][1]=input[i][j];
 	    }
	}

	/**** my addition *** NRP   ****/

	fscale = fopen("scale.dat","w");

	for(j = 0; j < ninattr; j++)
	{
	   fprintf(fscale,"%f %f\n",winput[j][0],winput[j][1]);
	}

	for (j=0; j < noutattr; j++)
	{
	   fprintf(fscale,"%f %f\n",wtarget[j][0],wtarget[j][1]);
	}

	fclose (fscale);

    /** My addition ends here *****/


         for(i = 0; i < ninput; i++)
	{
	    for(j = 0; j < ninattr; j++)
	    {
              if( ((winput[j][0]-winput[j][1])==0)&&(winput[j][0]!=0) )
		input[i][j] = input[i][j]/winput[j][0];
	      else if( ((winput[j][0]-winput[j][1])==0)&&(winput[j][0]==0) )
	      {      /* nothing to be done here */
		;
	      }
	      else
	       input[i][j] = (input[i][j] - winput[j][1])/(winput[j][0]-winput[j][1]);
 	    }
	}


    if((i = fclose(fpin)) != 0)
    {
	printf("\nFile cannot be closed %d", i);
	exit(0);
    }
    if((i = fclose(fpout)) != 0)
    {
	printf("\nFile cannot be closed %d", i);
	exit(0);
    }
}



/* ------------- Main body of the learning function --------------- */

void learning(learn_relearn)
int learn_relearn;
{
    int result, i;

    user_session();
    set_up();
    init();


    ep = (float *) calloc(ninput, sizeof(float));
    outpt = (float **) calloc(ninput, sizeof(float *));

    if((ep==NULL)||(outpt==NULL))
    {
       printf("Memory problem in learnig module at et/outpt.\n");
       exit(1);
    }

    for(i = 0; i < ninput; i++)
    {
	outpt[i] = (float *) calloc(noutattr, sizeof(float));
        if(outpt[i]==NULL)
        {
            printf("Memory problem in learnig module at outpt %d.\n",i);
            exit(1);
        }
    }

    do
    {
	if(learn_relearn == 1)
	    restorewt();
	else
	    initwt();


	    printf("******\n");


	result = rumelhart(0, ninput);

    } while(result == RESTRT);

    if(result == FEXIT)
    {
	printf("\n Max number of iterations reached, ");
	printf("\n   but failed to decrease system");
  	printf("\n   error sufficiently");
    }
    dwrite(task_name);
    wtwrite(task_name);
    free(ep);
    free(outpt);
}


/* ---------- Main body of the output generation function --------- */

void output_generation()
{
    int i, m, nsample,j;
    char dfile[50], ofile[50];
    float tmp;

    printf("\nGeneration of outputs for a new pattern");
    printf("\n\t Type the task name : ");
    scanf("%s", task_name);
    dread(task_name);
    init();
    wtread(task_name);

    printf("\nEnter file name for patterns to ");
    printf("be processes : \n");
    scanf("%s", dfile);

    printf("\nEnter file name for storing results \n");
    scanf("%s", ofile);

    if((fp1 = fopen(dfile, "r")) == NULL)
    {
	perror("Cannot open dfile");
	exit(0);
    }

    if((fp4 = fopen(ofile, "w")) == NULL)
    {
	perror("Cannot open ofile");
	exit(0);
    }

    printf("\nEnter number of patterns for processing : ");
    scanf("%d", &nsample);

    input = (float **) calloc(nsample, sizeof(float *));
    outpt = (float **) calloc(nsample, sizeof(float *));
    if((input==NULL)||(outpt==NULL))
    {
        printf("Memory problem in input/outpt \n");
        exit(1);
    } 

    for(i = 0; i < nsample; i++)
    {
	input[i] = (float *) calloc(ninattr, sizeof(float));
    	outpt[i] = (float *) calloc(noutattr, sizeof(float));
        if((input[i]==NULL)||(outpt[i]==NULL))
        {
            printf("Memory problem in input/outpt * at %d\n",i);
            exit(1);
        } 
    }

    /*** my addition *** NRP ***/

    wtarget = (float **) calloc(noutattr, sizeof(float *));
    winput  = (float **) calloc(ninattr,sizeof(float *));
  
    if((winput==NULL)||(wtarget==NULL))
    {
        printf("Memory problem in winput/wtarget\n");
        exit(1);
    } 

    for(i = 0; i < noutattr; i++)
    {
	wtarget[i] = (float *) calloc(2, sizeof(float));
        if(wtarget[i]==NULL)
        {
           printf("Memory problem in wtarget at %d\n",i);
           exit(1);
        } 
    }

    for (i=0; i < ninattr; i++)
    {
       winput[i] = (float *) calloc (2,sizeof(float));
       if(winput[i]==NULL)
       {
           printf("Memory problem in winput at %d\n",i);
           exit(1);
       } 
    }


    fscale = fopen("scale.dat","r");

    for (i=0; i < ninattr; i++)
       fscanf(fscale,"%f %f",&winput[i][0],&winput[i][1]);

    for (i=0; i < noutattr; i++)
	fscanf(fscale,"%f %f",&wtarget[i][0],&wtarget[i][1]);

	/**** my addition finishes ***/

    for(i = 0; i < nsample; i++)
    	for(m = 0; m < ninattr; m++)
	    fscanf(fp1, "%f", &input[i][m]);

    /******* my addition ***/

    for(i = 0; i < nsample; i++)
	{
	    for(j = 0; j < ninattr; j++)
	    {
              if(((winput[j][0]-winput[j][1])==0)&&(winput[j][0]==0))
	      {
	/*	printf("division by zero. line no 1031.\n");
		exit(1);
        */
	      }
              else if(((winput[j][0]-winput[j][1])==0)&&(winput[j][0]!=0))
	      {
                input[i][j] = (input[i][j]/winput[j][0]);
              }
              else
	      input[i][j] = (input[i][j] - winput[j][1])/(winput[j][0]-winput[j][1]);
/***	      printf("%f \n",input[i][j]); ***/
	    }
	}

/*** My addition finishes here *** NRP ********/


    for(i = 0; i < nsample; i++)
    {
	forward(i);

	for(m = 0; m < noutattr; m++)
	{
/*** old line

	    fprintf(fp4, "%f ", *(outptr[nhlayer+1]+m));

replaced by ******/

	    tmp = *(outptr[nhlayer+1]+m) * (wtarget[m][0]-wtarget[m][1]) +wtarget[m][1];
	    fprintf(fp4, "%f ", tmp);

	}
	fprintf(fp4, "\n");
    }

    printf("\nOutputs have been generated ");

    if((i = fclose(fp1)) != 0)
 	printf("\nFile cannot be closed %d", i);

    if((i = fclose(fp4)) != 0)
 	printf("\nFile cannot be closed %d", i);
}


/* ------------------------- Main program ------------------------- */

main()
{
    char select[20];

    system("clear");
    printf("\n\n** Select One Choice By Entering The First Letter **\n\n");
    printf("\nL(earning)\n");
    printf("\nR(esume learning)\n");
    printf("\nO(utput generation)\n");
    do
    {
	scanf("%s", select);
	switch(select[0])
	{
	    case 'o' :
	    case 'O' :
			output_generation();
			break;

	    case 'l' :
	    case 'L' :
			learning((int) 0);
			break;

	    case 'r' :
	    case 'R' :
			learning((int) 1);
			break;

	    default :
			printf("\nAnswer learning or output generation ");
			break;
	}
    } while((select[0] != 'o') && (select[0] != 'O') &&
	    (select[0] != 'l') && (select[0] != 'L') &&
	    (select[0] != 'r') && (select[0] != 'R'));
    printf("\nIt is all finished. ");
    printf("\n Good bye ");
}
